#ifndef ORG_WXW0303_COMMON_ERRNOEXCEPTION_H
#define ORG_WXW0303_COMMON_ERRNOEXCEPTION_H


#define THROW(errnum,...) \
    throw Exception (__PRETTY_FUNCTION__,\
                    errnum,\
                    ByteArray::format(__VA_ARGS__))

#include <stddef.h>
#include <stdexcept>
#include <utility>

#include "bytearray.h"



/* Exception;异常类,用于函数向外报告其内部发生的异常,有如下属性:
 *  functionName;记录了抛出异常的函数.
 *  errnum;错误码,建议使用当前已经定义的 errno 作为错误码.
 *  errstr;错误描述.
 */
class Exception: public std::exception {
public:
    Exception() = default;
    Exception(const ByteArray &fname,int errnum,const ByteArray &err);
    Exception(const ByteArray &fname,int errnum,ByteArray &&err);
    Exception(ByteArray &&fname,int errnum,const ByteArray &err);
    Exception(ByteArray &&fname,int errnum,ByteArray &&err);
    Exception(const Exception &e) = default;
    Exception(Exception &&e);
    Exception& operator =(const Exception &e) = default;
    Exception& operator =(Exception &&e);

    const ByteArray& functionName() const;
    void setFunctionName(const ByteArray &fName);

    const ByteArray& errstr() const;
    void setErrstr(const ByteArray &errstr);

    int errnum() const;
    void setErrnum(int errnum);

    const char* what() const noexcept override;
private:
    mutable ByteArray buf_for_what_;
    ByteArray fName_;
    ByteArray errstr_;
    int errnum_;
};

/* 当函数内发现所需缓冲区的大小超出用户提供的缓冲区大小,而且不被允许动态分配内存时,
 * 会通过该异常类来抛出异常.该类具有以下属性:
 * o needSize;函数所需的缓冲区大小.
 * o userProvideSize;用户提供的缓冲区大小.
 * o functionName(); 函数名.
 */
struct RangeException : public std::exception {
    RangeException() = default;
    RangeException(const ByteArray &functionName,size_t u,size_t n);

    const ByteArray& functionName() const;
    void setFunctionName(const ByteArray &fName);
    size_t userProvideSize() const;
    void setUserProvideSize(size_t u);
    size_t needSize() const;
    void setNeedSize(size_t n);

    const char* what() const noexcept override;
private:
    mutable ByteArray bufForWhat_;
    ByteArray functionName_;
    size_t userProvideSize_ = 0;
    size_t needSize_ = 0;
};

#define THROW_RANGE_EXCEPTION(needSize,userSize) \
    throw RangeException(__PRETTY_FUNCTION__,userSize,needSize)

////////RangeException Implement Begin//////////////////////////////////////////
inline RangeException::RangeException(const ByteArray &functionName,size_t u,size_t n):
    functionName_(functionName),userProvideSize_(u),needSize_(n)
{
}

inline const ByteArray& RangeException::functionName() const
{
    return functionName_;
}

inline void RangeException::setFunctionName(const ByteArray &fName)
{
    functionName_ = fName;
    return ;
}

inline size_t RangeException::userProvideSize() const
{
    return userProvideSize_;
}

inline void RangeException::setUserProvideSize(size_t u)
{
    userProvideSize_ = u;
    return ;
}

inline size_t RangeException::needSize() const
{
    return needSize_;
}

inline void RangeException::setNeedSize(size_t n)
{
    needSize_ = n;
    return ;
}

////////RangeException Implement Begin//////////////////////////////////////////

////////Exception Implement Begin///////////////////////////////////////////////
inline Exception::Exception(const ByteArray &fname,int errnum,const ByteArray &err):
    fName_(fname),errstr_(err),errnum_(errnum)
{
}

inline Exception::Exception(const ByteArray &fname,int errnum,ByteArray &&err):
    fName_(fname),errstr_(std::move(err)),errnum_(errnum)
{
}

inline Exception::Exception(ByteArray &&fname,int errnum,const ByteArray &err):
    fName_(std::move(fname)),errstr_(err),errnum_(errnum)
{
}

inline Exception::Exception(ByteArray &&fname,int errnum,ByteArray &&err):
    fName_(std::move(fname)),errstr_(std::move(err)),errnum_(errnum)
{
}

inline Exception::Exception(Exception &&e):
    fName_(std::move(e.fName_)),errstr_(std::move(e.errstr_)),errnum_(e.errnum_)
{
}

inline Exception& Exception::operator =(Exception &&e)
{
    fName_ = std::move(e.fName_);
    errstr_ = std::move(e.errstr_);
    errnum_ = e.errnum_;
    return *this;
}

inline const ByteArray& Exception::functionName() const
{
    return fName_;
}

inline void Exception::setFunctionName(const ByteArray &fName)
{
    fName_ = fName;
}

inline const ByteArray& Exception::errstr() const
{
    return errstr_;
}

inline void Exception::setErrstr(const ByteArray &errstr)
{
    errstr_ = errstr;
}

inline int Exception::errnum() const
{
    return errnum_;
}

inline void Exception::setErrnum(int errnum)
{
    errnum_ = errnum;
}

////////Exception Implement End/////////////////////////////////////////////////

#endif // ORG_WXW0303_COMMON_ERRNOEXCEPTION_H
